﻿using ArduinoSharp.Lib;
using System;
using System.Collections.Generic;
using System.IO.Ports;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

namespace ArduinoControllApp
{
    public delegate void SerialNewDataHandler(object sender, SerialEventArgs e);
    /// <summary>
    /// Interaction logic for serialPortUC.xaml
    /// </summary>
    public partial class serialPortUC : UserControl
    {
        private SerialPort comport = new SerialPort("COM1", 115200, Parity.None, 8, StopBits.One);

        public event SerialNewDataHandler onNewDataArived;

        public bool isOpened { get; set; }

        public serialPortUC()
        {
            InitializeComponent();
            InitialiseControlValues();

            this.isOpened = false;
            comport.DataReceived += new SerialDataReceivedEventHandler(port_DataReceived);
        }

        public void sendData(string data)
        {
            comport.WriteLine(data);
        }

        private void InitialiseControlValues()
        {


            //fill Ports in combobox
            PortNameCB.Items.Clear();
            SerialPort.GetPortNames().ToList()
                .ForEach(item => PortNameCB.Items.Add(item));

            //fill Parity in combobox
            ParityCB.Items.Clear();
            Enum.GetNames(typeof(Parity)).ToList()
                .ForEach(item => ParityCB.Items.Add(item));
            ParityCB.SelectedIndex = 0;

            //fill StopBits in combobox
            Enum.GetNames(typeof(StopBits)).ToList()
                .ForEach(item => StopBitsCB.Items.Add(item));
            StopBitsCB.SelectedIndex = 1;

            //fill DataBits in combobox
            var databits = new object[] {
            "7",
            "8",
            "9"};
            databits.ToList()
               .ForEach(item => DataBitsCB.Items.Add(item));
            DataBitsCB.SelectedIndex = 1;

            //fill Handshake in combobox
            Enum.GetNames(typeof(Handshake)).ToList()
                .ForEach(item => HandshakeCB.Items.Add(item));
            HandshakeCB.SelectedIndex = 0;


            //fill baudrates in combobox
            var baudrates = new object[] {
            "1200",
            "2400",
            "4800",
            "9600",
            "14400",
            "19200",
            "28800",
            "38400",
            "57600",
            "115200",
            "230400",
            "460800",
            "921600",
            "1328400"};
            baudrates.ToList().ForEach(item => BaudrateCB.Items.Add(item));
            BaudrateCB.SelectedIndex = 9;
            if (PortNameCB.Items.Count > 0) PortNameCB.SelectedIndex = 0;
            else
            {
                MessageBox.Show("There are no COM Ports detected on this computer.\nPlease install a COM Port and restart this app. No COM Ports Installed");
            }

            //fill Timeouts in comboboxes
            var Timeouts = new object[] {
            "50",
            "100",
            "250",
            "500",
            "1000",
            "2500",
            "5000"};
            Timeouts.ToList()
               .ForEach(item => ReadTimeoutCB.Items.Add(item));
            Timeouts.ToList()
               .ForEach(item => WriteTimeoutCB.Items.Add(item));
            ReadTimeoutCB.SelectedIndex = 1;
            WriteTimeoutCB.SelectedIndex = 1;



        }

        private void OpenBT_Click(object sender, RoutedEventArgs e)
        {
            if (comport.IsOpen)
            {
                comport.Close();
                this.isOpened = false;
                OpenBt.Content = "Open port";
            }
            else
            {
                var config = getConfig();

                if (!config.isValid)
                {
                    MessageBox.Show("Nesprávné nastavení seriového portu.", "Non valid Serial port set up.");
                    return;
                }
                config.SetToPort(comport);
                comport.Open();
                this.isOpened = true;
                OpenBt.Content = "Close Port";
            }
        }

        public SerialPortConfig getConfig()
        {
            try
            {
                return new SerialPortConfig
                {
                    isValid = true,
                    BaudRate = int.Parse(BaudrateCB.Text),
                    DataBits = int.Parse(DataBitsCB.Text),
                    StopBits = (StopBits)Enum.Parse(typeof(StopBits), StopBitsCB.Text),
                    Parity = (Parity)Enum.Parse(typeof(Parity), ParityCB.Text),
                    PortName = PortNameCB.Text,
                    ReadTimeout = int.Parse(ReadTimeoutCB.Text),
                    WriteTimeout = int.Parse(ReadTimeoutCB.Text),
                };
            }
            catch (ArgumentException)
            {
                return new SerialPortConfig
                {
                    isValid = false
                };
            }

        }

        private void port_DataReceived(object sender, SerialDataReceivedEventArgs e)
        {
            try
            {
                string inString;
                inString = comport.ReadLine();
                if (inString != null )
                {
                    var sd = new ArduinoSerialData(inString);
                    var ev = new SerialEventArgs(sd);
                    if (onNewDataArived != null)
                    {
                        onNewDataArived(this, ev);
                    }
                }
            }
            catch (TimeoutException){
                MessageBox.Show("Seriový port byl odpojen.");
            };

        }

        protected virtual void Dispose(bool disposing)
        {
            comport.Close();
        }
    }


}
